'use strict';

Object.defineProperty(exports, '__esModule', { value: true });

const random = Math.random;
const floor = Math.floor;

/**
 * 随机整数
 * @param {number} n
 * @returns [0, n)
 */
function intRand(n) {
  return floor(random() * n);
}

/**
 * 从范围[a, b)内随机
 * @param {number} a start
 * @param {number} b end
 * @returns [a, b)
 */
function rand(a, b) {
  if (b) {
    const diff = b - a;
    return a + intRand(diff);
  }
  return intRand(a);
}

/**
 * 分捆
 * @param {Array} array
 * @param {Number} size
 * @returns {Array}
 */
const chunk = (array, size = 1) => {
  let newArray = [];
  for (let i = 0; i < array.length; i = i + size) {
    newArray.push(array.slice(i, i + size));
  }
  return newArray;
};

/**
 * 扁平数组
 * @param {Array} array
 * @param {Number} depth
 * @returns {Array}
 */
const flat = (array, depth = 1) => {
  if (depth > 0) {
    return array.reduce((a, c) => {
      const cur = Array.isArray(c) ? flat(c, depth - 1) : [c];
      return [...a, ...cur];
    }, []);
  }
  return array.slice();
};

/**
 * 生成一个size大小的数组
 * @param {Number} size
 * @param {Function} func
 * @returns {Array}
 */
const map = (size, func = () => {}) => {
  return Array(size)
    .fill(0)
    .map((_, i) => func(i));
};

/**
 * 删除指定值
 * @param {Array} arr 源数组
 * @param  {Array} values 要删除的值
 */
const remove = (arr, ...values) =>
  arr.filter((e) => !values.includes(e));

/**
 * 返回数组合并结果
 * @param  {Array} arrays
 */
const union = (...arrays) => arrays.reduce((a, c) => a.concat(c), []);

/**
 * 交集
 * @param  {...any} array
 */
const intersection = (...arrays) =>
  arrays.reduce((a, c) => a.filter((e) => c.includes(e)));

/**
 * 差异
 */
const difference = (array, values) =>
  array.filter((v) => !values.includes(v));

/**
 * 比较
 */
const compare = (array, values) => [
  array.filter((v) => !values.includes(v)),
  values.filter((v) => !array.includes(v)),
];

const _compare = (array, values) => {
  const uniqueA = new Set(array);
  const uniqueV = new Set(values);

  for (const a of array) {
    for (const v of values) {
      if (a === v) {
        uniqueA.delete(a);
        uniqueV.delete(v);
        continue;
      }
    }
  }

  return [uniqueA.values(), uniqueV.values()].map((v) => Array.from(v));
};

/**
 * 交换
 */
function swap(array, i, j) {
  let temp = array[i];
  array[i] = array[j];
  array[j] = temp;
}

/**
 * 交换式洗牌
 */
const shuffle = (array) => {
  for (let i = array.length - 1; i > 0; i--) {
    swap(array, i, rand(i));
  }
};

/**
 * 蓄水池抽样
 * @param {Array} array 模拟大容量数组，长度为 N
 * @param {number} k 抽取K个 (K < N)
 */
const reservoir = (array, k) => {
  const pool = array.slice(0, k);

  let i = k + 1;
  while (i < array.length) {
    const r = rand(i); // [0, k+1)
    if (r < k) {
      pool[r] = array[i];
    }
    i++;
  }
  return pool;
};

exports._compare = _compare;
exports.chunk = chunk;
exports.compare = compare;
exports.difference = difference;
exports.flat = flat;
exports.intersection = intersection;
exports.map = map;
exports.remove = remove;
exports.reservoir = reservoir;
exports.shuffle = shuffle;
exports.union = union;
